/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/* exported BugLinks */

var BugLinks = (function() {
  var NOT_DONE_STATUSES = ['UNCONFIRMED', 'NEW', 'ASSIGNED', 'REOPENED'];
  var URL = '/buginfo/bug'; // TODO move this outside

  // from https://github.com/janl/mustache.js/blob/master/mustache.js#L82
  var entityMap = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#39;',
    '/': '&#x2F;',
  };
  function escapeHtml(string) {
    return String(string).replace(/[&<>"'/]/g, function(s) {
      return entityMap[s];
    });
  }

  function fetch_remotely(bug_ids) {
    var deferred = $.Deferred();
    var data = { bug_ids: bug_ids.join(',') };
    var req = $.getJSON(URL, data);
    req.done(function(response) {
      var table = {};
      $.each(response.bugs, function(i, each) {
        table[each.id] = each;
      });
      var fetched_bug_ids = [];
      $('.bug-link-without-data').each(function() {
        // we only fetched some bugs into `table` so
        // we might not have data on this one yet
        var $link = $(this);
        if ($link.data('id') in table) {
          $link.removeClass('bug-link-without-data').addClass('bug-link-with-data');
          var data = table[$link.data('id')];
          $link.data('summary', data.summary);
          $link.data('resolution', data.resolution);
          $link.data('status', data.status);
          fetched_bug_ids.push($link.data('id'));
        }
      });
      deferred.resolve($.unique(fetched_bug_ids));
    });
    req.fail(function() {
      deferred.reject();
    });
    return deferred.promise();
  }

  function fetch(bug_ids) {
    var batch_size = 100;
    var i = 0,
      j = 0;
    while (i < bug_ids.length) {
      j += batch_size;
      // For each batch, do an XHR on the data
      // which also appends that fetched data to each link tag.
      // When the data has been downloaded and attached to
      // each link tag run this to update
      fetch_remotely(bug_ids.slice(i, j)).done(transform_with_data);
      i = j;
    }
  }

  function transform_with_data() {
    // this function is potentially called repeated every time
    // fetch_without_data() has fetched more data for the links
    $('.bug-link-with-data').each(function() {
      var $link = $(this);
      if ($link.data('transformed')) return; // already done
      var status = $link.data('status');
      var resolution = $link.data('resolution') || '---';
      var summary = $link.data('summary');

      var combined = status + ' ' + resolution + ' ' + summary;
      $link.attr('title', escapeHtml(combined));
      if ($link.parents('.bug_ids_expanded_list').length) {
        $link.after($('<span class="bug-summary">').text(combined));
      }
      if (status && $.inArray(status, NOT_DONE_STATUSES) === -1) {
        $link.addClass('strike');
      }
      $link.data('transformed', true);
    });
  }

  function fetch_without_data() {
    // in batches, do a XHR to pull down more details about bugs
    // for those bug links that don't have data yet
    var unique_bug_ids = [];
    $('.bug-link-without-data').each(function() {
      unique_bug_ids.push($(this).data('id'));
    });
    unique_bug_ids = $.unique(unique_bug_ids);
    if (unique_bug_ids.length) {
      fetch(unique_bug_ids);
    }
  }

  return {
    /* Enhance bug links using metadata about the bug. */
    enhance: function() {
      // apply to all bug links that already have the data
      // when the template was rendered
      transform_with_data();
      // XHR fetch all other ones
      fetch_without_data();
    },
    /* Enhance bug links and expanded bug lists. */
    enhanceExpanded: function() {
      this.enhance();

      $('.bug_ids_more').hover(function() {
        if (!$('.bug-link', this).length) return;
        var inset = 10;
        var $cell = $(this);
        var bugList = $cell.find('.bug_ids_expanded_list');
        bugList
          .css({
            top: $cell.position().top - inset,
            left: $cell.position().left - (bugList.width() + inset),
          })
          .toggle();
      });
    },
  };
})();
